#pragma once
#include"Common.hpp"
namespace ThreadPoolMudole {
    template<typename T>
    class ThreadPool{
        private:
           
            void WakeUp(){
                LockGuard lock(_mutex);
                {
                if(_sleepernum>0)
                _cond.Broadcast();
                LOG(LogLevel::INFO)<< "All Threads are WakeUp";
                }
            }
            void WakeUpone(){
                LockGuard lockguard(_mutex);
                {
                    if(_sleepernum>0)
                    _cond.Signal();
                    LOG(LogLevel::INFO)<< "One Thread is WakeUp";
                }
            }
        public:
            ThreadPool(int num=5):_num(num),_isrunning(false),_sleepernum(0),_isdetach(false){
                for(int i=0;i<num;++i){
                    _threads.emplace_back([this](){
                        HandlerTask();
                    });
                }
                LOG(LogLevel::INFO)<<"create new ThreadPool"<<num;
            }
             void Join(){
                for(auto&t:_threads){
                    t.Join();
                }
            }
            void Detch(){
                if(_isdetach)return;
                _isdetach=true;
                for(auto&t:_threads){
                    t.Detach();
                }
                LOG(LogLevel::INFO)<<"this ThreadPool is detach"; 
            }
            void HandlerTask(){
                T t;
                Enable_Console_Log;
               while(true){
                {
                LockGuard lockguard(_mutex);
                while(_taskq.empty()&&_isrunning){
                    _sleepernum++;
                    LOG(LogLevel::INFO)<<"thread is block";
                    _cond.Wait(&_mutex);
                    LOG(LogLevel::INFO)<<"ThreadPool get a task";
                    _sleepernum--;
                }
                if(!_isrunning&&_taskq.empty()){
                    LOG(LogLevel::INFO)<< "ThreadPool is stoped";
                    break;
                }
                //内部线程被唤醒
                //一定有任务
                
                t=std::move(_taskq.front());
                _taskq.pop();
                }
                LOG(LogLevel::INFO)<<"ThreadPool handle a task";
                t();
               }
            }
            ~ThreadPool(){}
            void Start(){
                if(_isrunning)return;
                _isrunning=true;
                for(auto& t:_threads){
                    t.Start();
                }
            }
            void Stop(){
                if(!_isrunning)return;
                _isrunning = false;
                //通知所有线程
                WakeUp();               
            }
            bool Enqueue(const T& t){
                LockGuard lockguard(_mutex);
                if(!_isrunning){
                    LOG(LogLevel::ERROR)<< "ThreadPool is not running";
                    return false;
                }
                LOG(LogLevel::INFO)<< "enqueue a task";
                _taskq.push(t);
                //通知一个线程
                WakeUp();
                return true;
            }
        private:
            int _num;
            std::vector<Thread> _threads;
            std::queue<T> _taskq;//任务队列
            Cond _cond;//条件变量
            Mutex _mutex;//互斥锁
            bool _isrunning;
            int _sleepernum;//休眠者的数量
            int _isdetach;//是否分离
    };
}